#pragma once
#ifndef UTILS_H_
#define UTILS_H_

#include <array>
#include <vector>
#include <string>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "unetv1.h"

void load_ifm(data_stream<BIT_ACTV>& ifm, unsigned length, std::string path)
{
    uint8_t* ifm_buffer;
    ifm_buffer = (uint8_t*)malloc(length*sizeof(uint8_t));
    FILE *fp = fopen(path.c_str(), "rb");
    fread(ifm_buffer, 1, length*sizeof(uint8_t), fp);
    fclose(fp);

    for(size_t i=0; i < length; i++)
    {
        ifm.write(ifm_buffer[i]);
    }
    free(ifm_buffer);
}

template<size_t N>
void gen_ifm(data_stream<BIT_ACTV>& ifm, std::array<unsigned, N> shape) {
	unsigned length = 1;
	for(size_t i = 0; i < N; i++) {
		length *= shape[i];
	}
	for(size_t i = 0; i < length; i++)	{
		ifm.write(i); // Example data generation, can be modified as needed
	}
}

template<unsigned DWIDTH, size_t N>
uint32_t check_afm(data_stream<DWIDTH>& golden, data_stream<DWIDTH>& test, std::array<unsigned, N> shape, bool print = false) {
	unsigned length = 1;
	for(size_t i = 0; i < N; i++)
	{
		length *= shape[i];
	}
    uint32_t* ofm_buffer;
    ofm_buffer = (uint32_t*)malloc(length*sizeof(uint32_t));

	uint32_t error_cnt = 0;

	if(print) std::cout << "golden: " << std::endl;
	for(size_t i=0; i < length; i++)
	{
		if(i % shape[N-1] == 0)
		{
			if(print) std::cout << std::endl;
		}
		ofm_buffer[i] = golden.read();
		if(print)  std::cout << std::setfill(' ') << std::setw(4) << (int32_t)ofm_buffer[i] << " ";
	}
	if(print)  std::cout << std::endl;

	if(print)  std::cout << "test: " << std::endl;
	for(size_t i=0; i < length; i++)
	{
		if(i % shape[N-1] == 0)
		{
			if(print) std::cout << std::endl;
		}
		auto temp = test.read();
		if(print)  std::cout << std::setfill(' ') << std::setw(4) << (int32_t)temp << " ";
		if(temp != ofm_buffer[i])
		{
			error_cnt++;
		}
	}
	if(print)  std::cout << std::endl;
	return error_cnt;
}


#endif
